package com.gome.boot.common.diamond;

import com.gome.boot.common.logger.BaseLogger;
import com.gome.boot.common.util.CommonUtils;
import com.gome.boot.common.util.FileUtils;
import com.taobao.diamond.manager.DiamondManager;
import com.taobao.diamond.manager.ManagerListener;
import com.taobao.diamond.manager.ManagerListenerAdapter;
import com.taobao.diamond.manager.impl.DefaultDiamondManager;

import java.io.IOException;
import java.io.StringReader;
import java.util.*;

/**
 * Diamond配置加载工具类.
 * <br/>支持多个配置数据加载.
 *
 * @author baoxiufeng
 */
public class MultiDiamondUtils extends BaseLogger {
    /**
     * 默认Diamond配置文件路径
     */
    public static final String DEFAULT_CONFIG_FILE_PATH = System.getProperty("user.home") + "/.diamond.domain";

    /**
     * 加载Diamond配置内容超时时间.
     */
    private static final long LOAD_DIAMOND_TIMEOUT = 5000L;

    /**
     * 列表值分隔符.
     */
    private static final String LIST_SEPARATOR = ",";

    /**
     * 集合值分隔符
     */
    private static final String MAP_SEPARATOR = "=";

    /**
     * Diamond服务节点配置文件路径
     */
    private String configFilePath;

    /**
     * Diamond服务节点地址（IP或域名）
     */
    private String diamondIpList;

    /**
     * Diamond配置对象列表
     */
    private List<DiamondBean> diamondBeanList;

    /**
     * Diamond配置内容集合
     */
    private Properties configProps;

    /**
     * Diamond配置内容加载辅助对象
     */
    private Properties props;

    /**
     * 默认构造方法.
     */
    public MultiDiamondUtils() {
    }

    /**
     * 采用默认节点配置文件构建Diamond配置加载工具类，并加载配置内容.
     *
     * @param diamondBeanList 需要加载的Diamond配置对象列表
     * @return Diamond配置加载工具类
     */
    public static MultiDiamondUtils build(List<DiamondBean> diamondBeanList) {
        return build(DEFAULT_CONFIG_FILE_PATH, diamondBeanList);
    }

    /**
     * 采用指定节点配置文件构建Diamond配置加载工具类，并加载配置内容.
     *
     * @param configFilePath Diamond服务节点配置文件路径
     * @param diamondBeanList 需要加载的Diamond配置对象列表
     * @return Diamond配置加载工具类
     */
    public static MultiDiamondUtils build(String configFilePath, List<DiamondBean> diamondBeanList) {
        MultiDiamondUtils util = new MultiDiamondUtils();
        util.configFilePath = configFilePath;
        util.diamondBeanList = diamondBeanList;
        util.init();
        return util;
    }

    /**
     * 初始化配置并加载Diamond配置内容。
     */
    public void init() {
        if (CommonUtils.isEmpty(configFilePath)) {
            configFilePath = DEFAULT_CONFIG_FILE_PATH;
        }
        this.diamondIpList = FileUtils.readFileContent(configFilePath);
        logger.info("[MultiDiamondUtils.init] Read diamondIpList [{}] from file:{}", diamondIpList, configFilePath);
        if (CommonUtils.isEmpty(diamondIpList)) {
            logger.error("[MultiDiamondUtils.init] DiamondIpList is null or empty.");
            return;
        }
        logger.error("[MultiDiamondUtils.init] DiamondIpList:{}", diamondIpList);
        if (CommonUtils.isNotEmpty(diamondBeanList)) {
            ManagerListener listener = new ManagerListenerAdapter() {
                @Override
                public void receiveConfigInfo(String s) {
                    MultiDiamondUtils.this.loadConfigToMap(s);
                }
            };
            DiamondManager manager = null;
            for (DiamondBean diamondBean : diamondBeanList) {
                if (CommonUtils.isNoneBlank(diamondBean.getGroup(), diamondBean.getDataId())) {
                    manager = new DefaultDiamondManager(diamondBean.getGroup(), diamondBean.getDataId(), listener, diamondIpList);
                    String configContent = manager.getAvailableConfigureInfomation(LOAD_DIAMOND_TIMEOUT);
                    this.loadConfigToMap(configContent);
                } else {
                    logger.error("[MultiDiamondUtils.init] Diamond数据配置属性异常: Group={}, DataId:{}", diamondBean.getGroup(), diamondBean.getDataId());
                }
            }
        } else {
            logger.error("[MultiDiamondUtils.init] DiamondBeanList is null or empty.");
        }
    }

    /**
     * 加载配置内容到集合中.
     *
     * @param configContent 待加载的配置内容
     */
    private void loadConfigToMap(String configContent) {
        if (CommonUtils.isNotEmpty(configContent)) {
            if (this.props == null) {
                this.props = new Properties();
            }
            try {
                this.props.load(new StringReader(configContent));
                this.configProps = props;
            } catch (IOException e) {
                logger.error("[MultiDiamondUtils.loadConfigToMap] Diamond数据内容加载失败:{}", e.getMessage());
            }
        }
    }

    /**
     * 从Diamond配置中获取指定KEY对应的VALUE.
     *
     * @param key 需要查询的KEY
     * @return 查询KEY对应的值，如果配置内容集合不存在，则返回null
     */
    public Object getValue(Object key) {
        return CommonUtils.isEmpty(configProps) ? null : configProps.get(key);
    }

    /**
     * 从Diamond配置中获取指定KEY对应的值列表.
     *
     * @param key 需要查询的KEY
     * @return 查询KEY对应的值列表，如果配置内容集合不存在，则返回null
     */
    public List<String> getValues(Object key) {
        String value = (String) this.getValue(key);
        if (CommonUtils.isNotEmpty(value)) {
            return Arrays.asList(value.trim().split(LIST_SEPARATOR));
        }
        return null;
    }

    /**
     * 从Diamond配置中获取指定KEY对应的值集合.
     *
     * @param key 需要查询的KEY
     * @return 查询KEY对应的值集合，如果配置内容集合不存在，则返回null
     */
    public Map<String, String> getValueMap(Object key) {
        String value = (String) this.getValue(key);
        if (CommonUtils.isNotEmpty(value)) {
            String[] ss = value.trim().split(LIST_SEPARATOR);
            Map<String, String> map = new HashMap<String, String>(ss.length);
            for (String s : ss) {
                if (CommonUtils.isEmpty(s)) {
                    continue;
                }
                String[] kv = s.split(MAP_SEPARATOR);
                if (kv.length == 2) {
                    map.put(kv[0], kv[1]);
                }
            }
        }
        return null;
    }

    public String getConfigFilePath() {
        return configFilePath;
    }

    public void setConfigFilePath(String configFilePath) {
        this.configFilePath = configFilePath;
    }

    public String getDiamondIpList() {
        return diamondIpList;
    }

    public void setDiamondIpList(String diamondIpList) {
        this.diamondIpList = diamondIpList;
    }

    public List<DiamondBean> getDiamondBeanList() {
        return diamondBeanList;
    }

    public void setDiamondBeanList(List<DiamondBean> diamondBeanList) {
        this.diamondBeanList = diamondBeanList;
    }

    public Properties getConfigProps() {
        return configProps;
    }
}
